package main

import (
	"encoding/json"
	"fmt"
	"gitee.com/gzhtty_1824517828/go-gin-gorm/dao/po"
	"gitee.com/gzhtty_1824517828/go-gin-gorm/middleware"
	"github.com/gin-gonic/gin"
	"gitlab.phadata.net/fujie/logger"
	"gorm.io/driver/mysql"
	_ "gorm.io/driver/mysql"
	"gorm.io/gorm"
	gormLog "gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"net/http"
	"strconv"
	"strings"
)

func main() {
	db, err := gorm.Open(mysql.Open("root:root@(47.100.162.114:13306)/role?charset=utf8mb4&parseTime=True&loc=Local"),
		&gorm.Config{
			Logger: gormLog.Default.LogMode(gormLog.Info),
			NamingStrategy: schema.NamingStrategy{
				//TablePrefix:   "t_", // 表名前缀，`User`表为`t_users`
				SingularTable: true, // 使用单数表名，启用该选项后，`User` 表将是`user`
			},
		},
	)
	if err != nil {
		panic("failed to connect database")
	}

	//创建路由
	r := gin.New()
	//注册跨域中间单
	r.Use(middleware.Cors())
	r.Use(middleware.JwtAuth())
	config := logger.LogConfig{
		Level:         "info",
		Path:          "./logs/log.log",
		MaxSize:       1,
		MaxAge:        1,
		MaxBackups:    1,
		LocalTime:     false,
		JsonEncoder:   false,
		Compress:      true,
		ConsoleStdout: true,
		FileStdout:    true,
	}
	//初始化日志配置
	logger.InitLogger(config)
	//是否打印请求参数，响应结果
	r.Use(logger.GinLogger(true))
	// 打印报错栈日志
	r.Use(logger.GinRecovery(true))

	// 2.绑定路由规则，执行的函数
	// gin.Context，封装了request和response
	r.GET("/1")

	r.GET("/name/:name", func(context *gin.Context) {
		pathParam := context.Param("name")
		context.String(http.StatusOK, "%s", pathParam)
	})
	r.GET("/age/:age/*name", func(context *gin.Context) {
		param := context.Param("age")
		name := context.Param("name")
		fmt.Println(param)
		fmt.Println(name)
		trim := strings.Trim(name, "/")
		fmt.Println(trim)
		context.String(http.StatusOK, "%s%s", param, trim)
	})

	//get的query传参
	r.GET("/user", func(context *gin.Context) {
		name := context.DefaultQuery("name", "linx")
		//模拟查询数据库
		/*user := struct {
			Name    string
			Age     int
			Address string
		}{
			name,
			18,
			"北京天安门",
		}*/
		context.JSON(http.StatusOK, struct {
			Name    string
			Age     int
			Address string
		}{
			name,
			18,
			"北京天安门",
		})
	})

	//表单传输
	r.POST("/form", func(context *gin.Context) {
		form := context.PostForm("name")
		fmt.Println(form)
		postForm := context.DefaultPostForm("age", "1800")
		fmt.Println(postForm)
		//reqParam := make(map[string]interface{})
		reqParam := ReqParam{}
		/**
		前端传的json自己定义结构体也可以定义map来接收
		*/
		var insetUser po.User
		insetUser.Name = "linx"
		insetUser.Age = 18
		//插入数据
		db.Create(&insetUser)
		context.ShouldBindJSON(&reqParam)
		name := reqParam.Name
		var userResult po.User
		//操作数据库
		db.Find(&userResult, "name=?", name)
		context.JSON(http.StatusOK, userResult)
	})

	//上传单个文件
	r.POST("/upload", func(context *gin.Context) {
		file, err := context.FormFile("file")
		apiResult := ApiResult{}
		if err != nil {
			apiResult.Code = http.StatusBadRequest
			apiResult.Message = http.StatusText(http.StatusBadRequest)
			apiResult.Payload = err.Error()
			context.JSON(http.StatusOK, apiResult)
			return
		}
		fmt.Println(file.Filename, file.Size)
		//TODO 这里save我不知道具体干了什么
		err = context.SaveUploadedFile(file, file.Filename)
		if err != nil {
			apiResult.Code = http.StatusInternalServerError
			apiResult.Message = "服务端保存file失败"
			apiResult.Payload = err.Error()
			context.JSON(http.StatusOK, apiResult)
			return
		}
		apiResult.Code = http.StatusOK
		apiResult.Message = http.StatusText(http.StatusOK)
		apiResult.Payload = file.Filename
		context.JSON(http.StatusOK, apiResult)
	})

	//上传多个文件
	// 限制表单上传大小 8MB，默认为32MB
	r.MaxMultipartMemory = 8 << 20
	r.POST("/uploads", func(context *gin.Context) {
		//所有file
		files, err := context.MultipartForm()
		//响应数据
		var apiResult ApiResult
		if err != nil {
			apiResult.Code = http.StatusBadRequest
			apiResult.Message = http.StatusText(http.StatusBadRequest)
			apiResult.Payload = err.Error()
			context.JSON(http.StatusOK, apiResult)
			return
		}
		fileAll := files.File["file"]
		payload := map[string]string{}
		for index, elementFile := range fileAll {
			err = context.SaveUploadedFile(elementFile, elementFile.Filename)
			if err != nil {
				apiResult.Code = http.StatusInternalServerError
				apiResult.Message = "服务端保存file失败"
				apiResult.Payload = err.Error()
				context.JSON(http.StatusOK, apiResult)
				return
			}
			payload[strconv.Itoa(index)] = elementFile.Filename
		}
		apiResult.Code = http.StatusOK
		apiResult.Message = http.StatusText(http.StatusOK)
		apiResult.Payload = payload
		context.JSON(http.StatusOK, apiResult)
	})

	//路由分组
	v1 := r.Group("v1")
	{
		v1.GET("", func(context *gin.Context) {
			context.JSON(http.StatusOK, "v1 get")
		})
		v1.POST("", func(context *gin.Context) {
			context.JSON(http.StatusOK, "v1 post")
		})
	}
	v2 := r.Group("v2")
	{
		v2.GET("", v2Get)
		v2.POST("", v2Post)
	}
	r.LoadHTMLGlob("templates/*")
	v3 := r.Group("/v3")
	{
		v3.GET("/index.html", Index)
		v3.GET("/redirect", Redirect)
	}
	r.Run(":18080")
}

// Redirect 重定向
func Redirect(ctx *gin.Context) {
	get, exists := ctx.Get("cors")
	fmt.Println("exists =", exists, "get =", get)
	ctx.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")
}

// Index 首页
func Index(ctx *gin.Context) {
	result := struct {
		Title    string `json:"title"`
		PageInfo string `json:"pageInfo"`
	}{
		"linx first",
		"hello world",
	}
	var data map[string]interface{}
	marshal, err := json.Marshal(result)
	if err != nil {
		println(err.Error())
		return
	}
	err1 := json.Unmarshal(marshal, &data)
	if err1 != nil {
		println(err1.Error())
		return
	}
	fmt.Println(result)
	fmt.Println(data)
	ctx.HTML(http.StatusOK, "index.html", data)
	//ctx.HTML(http.StatusOK,"index.html",gin.H{"title":"linx first","pageInfo":"hello world"})
}
func v2Get(context *gin.Context) {
	context.JSON(http.StatusOK, "v2 get")
}
func v2Post(context *gin.Context) {
	context.JSON(http.StatusOK, "v2 post")
}

type ReqParam struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}
type ApiResult struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Payload interface{} `json:"payload"`
}
